package service

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	log "github.com/sirupsen/logrus"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"usbipproxy/common"
	"usbipproxy/common/platform"
	"usbipproxy/domain/vo"
)

var onceRun sync.Once

type UsbIpClientWindowsCmdServiceImpl struct {
	//     sync.RWMutex
	//attachMap      map[int64]bool
	platformHandle platform.PlatformHandler
}

func (u *UsbIpClientWindowsCmdServiceImpl) SetDefaultAudioDevice(index int, deviceType string, isCommunication bool) error {
	// 获取所有设备以验证索引有效性
	devices, err := u.GetAudioDeviceList()
	if err != nil {
		log.Errorf("获取音频设备失败: %v", err)
		return err
	}

	// 验证索引是否有效
	var found bool
	var deviceName string
	for _, device := range devices {
		if device.Index == index && device.Type == deviceType {
			found = true
			deviceName = device.Name
			break
		}
	}

	if !found {
		log.Errorf("未找到索引为 %d 的 %s 设备", index, deviceType)
		return fmt.Errorf("not find %v device %v", index, deviceType)
	}

	// 构建 PowerShell 命令
	var cmd string
	if isCommunication {
		cmd = fmt.Sprintf("Set-AudioDevice -Index %d -CommunicationDefault", index)
	} else {
		if deviceType == "Playback" {
			cmd = fmt.Sprintf("Set-AudioDevice -Index %d", index)
		} else if deviceType == "Recording" {
			//cmd = fmt.Sprintf("Set-AudioDevice -Index %d -Type Recording", index)
			//麦克风不设置？
		}
	}

	if cmd == "" {
		log.Infof("cmd none skip")
		return nil
	}

	log.Infof("SetDefaultAudioDevice cmd:%v", cmd)
	// 执行命令
	_, stderr, err := common.RunPowerShellCommand("-Command", cmd)
	if err != nil {
		log.Infof("设置默认设备失败: %v, 错误信息: %s", err, stderr)
		return err
	}

	log.Infof("成功设置 %s (%s) 为默认%s设备\n", deviceName, deviceType, map[bool]string{true: "通信", false: ""}[isCommunication])
	return nil
}

func (u *UsbIpClientWindowsCmdServiceImpl) GetAudioDeviceList() ([]vo.AudioDevice, error) {
	// 执行 Get-AudioDevice 命令
	//stdout, stderr, err := common.RunPowerShellCommand("-Command", "Get-AudioDevice -List")
	stdout, stderr, err := common.RunPowerShellCommand("[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-AudioDevice -List")
	if err != nil {
		return nil, fmt.Errorf("命令执行失败: %v, 错误输出: %s", err, stderr)
	}

	//log.Infof("GetAudioDeviceList stdout: %s", stdout)
	// 解析命令输出
	return u.parseAudioDeviceOutput(stdout)
}

// parseAudioDeviceOutput 解析 PowerShell 命令输出
func (u *UsbIpClientWindowsCmdServiceImpl) parseAudioDeviceOutput(output string) ([]vo.AudioDevice, error) {
	var devices []vo.AudioDevice
	var currentDevice vo.AudioDevice
	scanner := bufio.NewScanner(strings.NewReader(output))

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())

		// 跳过空行
		if line == "" {
			// 如果当前设备有数据，添加到列表
			if currentDevice.Index > 0 {
				devices = append(devices, currentDevice)
				currentDevice = vo.AudioDevice{}
			}
			continue
		}

		// 解析键值对
		if strings.Contains(line, ":") {
			parts := strings.SplitN(line, ":", 2)
			if len(parts) != 2 {
				continue
			}

			key := strings.TrimSpace(parts[0])
			value := strings.TrimSpace(parts[1])

			switch key {
			case "Index":
				if idx, err := strconv.Atoi(value); err == nil {
					currentDevice.Index = idx
				}
			case "Default":
				currentDevice.Default = strings.EqualFold(value, "True")
			case "DefaultCommunication":
				currentDevice.DefaultCommunication = strings.EqualFold(value, "True")
			case "Type":
				currentDevice.Type = value
			case "Name":
				currentDevice.Name = value
			case "ID":
				currentDevice.ID = value
			case "Device":
				currentDevice.Device = value
			}
		}
	}

	// 添加最后一个设备（如果没有空行结尾）
	if currentDevice.Index > 0 {
		devices = append(devices, currentDevice)
	}

	return devices, nil
}

func (u *UsbIpClientWindowsCmdServiceImpl) ensureAudioDeviceModule() error {
	//记得power 手动装 Install-Module -Name AudioDeviceCmdlets -Scope CurrentUser -Force -AllowClobber
	//return nil
	// 检查是否已安装模块
	stdout, stderr, err := common.RunPowerShellCommand("-Command", "Get-Module -ListAvailable -Name AudioDeviceCmdlets")

	if err != nil || strings.Contains(stderr, "not recognized") || stdout == "" {
		log.Infof("未找到 AudioDeviceCmdlets 模块，正在安装... err:%v", err)

		// 设置执行策略以允许安装模块
		_, _, err := common.RunPowerShellCommand("-Command", "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force -Confirm:$false")
		if err != nil {
			return fmt.Errorf("设置执行策略失败: %v", err)
		}

		// 安装模块
		//_, stderr, err := common.RunPowerShellCommand("-Command", "Install-Module -Name AudioDeviceCmdlets -Scope CurrentUser -Force -AllowClobber -Confirm:$false")
		//_, stderr, err := common.RunPowerShellCommand("-Command", "Install-Module -Name AudioDeviceCmdlets -Scope CurrentUser -Force")
		_, stderr, err := common.RunPowerShellCommand("-Command",
			"Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Confirm:$false")
		if err != nil && !strings.Contains(stderr, "已经安装") {
			// 如果上述方法失败，尝试使用管道传递 "Y"
			_, stderr, err = common.RunPowerShellCommand("-Command",
				"echo 'Y' | Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force")
			if err != nil && !strings.Contains(stderr, "已经安装") {
				return fmt.Errorf("安装 NuGet 提供程序失败: %v, 错误信息: %s", err, stderr)
			}
		}
		if err != nil {
			return fmt.Errorf("安装模块失败: %v, 错误信息: %s", err, stderr)
		}

		// 等待一段时间确保 NuGet 提供程序已完全安装
		//time.Sleep(2 * time.Second)

		// 安装模块 - 使用多种方法确保自动化
		log.Println("正在安装 AudioDeviceCmdlets 模块...")
		_, stderr, err = common.RunPowerShellCommand("-Command",
			"Install-Module -Name AudioDeviceCmdlets -Scope CurrentUser -Force -AllowClobber -Confirm:$false")
		if err != nil {
			// 如果上述方法失败，尝试使用管道传递 "Y"
			_, stderr, err = common.RunPowerShellCommand("-Command",
				"echo 'Y' | Install-Module -Name AudioDeviceCmdlets -Scope CurrentUser -Force -AllowClobber")
			if err != nil {
				return fmt.Errorf("安装模块失败: %v, 错误信息: %s", err, stderr)
			}
		}
		log.Println("AudioDeviceCmdlets 模块安装成功")
	} else {
		log.Println("AudioDeviceCmdlets 模块已安装")
	}

	return nil
}

/*
func (u *UsbIpClientWindowsCmdServiceImpl) LenAttachMap() int {
	//u.attachLock.RLock()
	//defer u.attachLock.RUnlock()

	//return len(u.attachMap)
}

func (u *UsbIpClientWindowsCmdServiceImpl) checkAttach() string {
	//检测如果断掉了 就detach掉
	ticker := time.NewTicker(time.Second * 3)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C:
			if u.LenAttachMap() == 0 {
				//log.Infof("checkAttach LenAttachMap:%v", u.LenAttachMap())
				continue
			}
			portList := u.PortList()
			portListByte, _ := json.Marshal(portList)
			log.Debugf("checkAttach portListByte:%v", string(portListByte))
			if len(portList) != u.LenAttachMap() {
				u.attachLock.Lock()
				for connId := range u.attachMap {
					u.DetachByParent(connId)
					delete(u.attachMap, connId)
				}
				u.attachLock.Unlock()
			}
		}
	}
}
*/

// MMDeviceUtil.exe -e detach_by_parent -s 1 -P "SWD\USBIP2\1958797317062524928"
func (u *UsbIpClientWindowsCmdServiceImpl) DetachByParent(connId int64) (bool, error) {
	exePath, _ := os.Executable()
	exeDir := filepath.Dir(exePath)
	absExeDir, _ := filepath.Abs(exeDir)
	parentDir := filepath.Dir(absExeDir)
	absParentDir, _ := filepath.Abs(parentDir)

	log.Infof("DetachByParent connId:%v absParentDir:%v", connId, absParentDir)
	sid, _ := u.platformHandle.GetCurrentSessionID()
	filePath, _ := common.FindOneFile(absParentDir, "MMDeviceUtil.exe")

	if filePath == "" {
		log.Errorf("can not find the MMDeviceUtil.exe path")
		return false, errors.New("can not find the filepath of MMDeviceUtil.exe")
	}

	cmdStrs := []string{filePath, "-e", "detach_by_parent", "-s", fmt.Sprintf("%v", sid), "-P",
		fmt.Sprintf("SWD\\USBIP2\\%v", connId)}
	log.Infof("DetachByParent cmdStrs:%+v", cmdStrs)
	cmdOutput, err := exec.Command(cmdStrs[0], cmdStrs[1:]...).CombinedOutput()
	if err != nil {
		log.Errorf("DetachByParent err:%v cmdOutput:%v", err, string(cmdOutput))
		return false, err
	}

	log.Infof("DetachByParent cmdOutput:%v", string(cmdOutput))
	return true, nil
}

// MMDeviceUtil.exe -e attach_by_parent -s 1 -P "SWD\USBIP2\1958797317062524928"
func (u *UsbIpClientWindowsCmdServiceImpl) AttachByParent(connId int64) (bool, error) {
	//u.attachLock.Lock()
	//u.attachMap[connId] = true
	//u.attachLock.Unlock()

	exePath, _ := os.Executable()
	exeDir := filepath.Dir(exePath)
	absExeDir, _ := filepath.Abs(exeDir)
	parentDir := filepath.Dir(absExeDir)
	absParentDir, _ := filepath.Abs(parentDir)

	log.Infof("AttachByParent connId:%v absParentDir:%v", connId, absParentDir)
	sid, _ := u.platformHandle.GetCurrentSessionID()
	filePath, _ := common.FindOneFile(absParentDir, "MMDeviceUtil.exe")

	if filePath == "" {
		log.Errorf("can not find the MMDeviceUtil.exe path")
		return false, errors.New("can not find the filepath of MMDeviceUtil.exe")
	}

	//u.addToPath(filepath.Dir(filePath))

	cmdStrs := []string{filePath, "-e", "attach_by_parent", "-s", fmt.Sprintf("%v", sid), "-P",
		fmt.Sprintf("SWD\\USBIP2\\%v", connId)}
	log.Infof("AttachByParent cmdStrs:%+v", cmdStrs)

	//cmdStr := fmt.Sprintf(`%v -e attach_by_parent -s %v -P "SWD\USBIP2\%v"`, "MMDeviceUtil.exe", sid, connId)
	//cmd := exec.Command("runas", "/user:Administrator", cmdStr)
	//cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
	cmdOutput, err := exec.Command(cmdStrs[0], cmdStrs[1:]...).CombinedOutput()
	//cmdOutput, err := cmd.CombinedOutput()
	if err != nil {
		log.Errorf("AttachByParent err:%v cmdOutput:%v", err, string(cmdOutput))
		return false, err
	}

	log.Infof("AttachByParent cmdOutput:%v", string(cmdOutput))

	return true, nil
}

func (u *UsbIpClientWindowsCmdServiceImpl) addToPath(dir string) error {
	log.Infof("addToPath dir:%v", dir)
	// 获取当前PATH
	currentPath := os.Getenv("PATH")

	// 确保目录存在且是绝对路径
	absDir, err := filepath.Abs(dir)
	if err != nil {
		return fmt.Errorf("获取绝对路径失败: %v", err)
	}

	// 检查目录是否已经在PATH中
	pathDirs := strings.Split(currentPath, string(os.PathListSeparator))
	for _, pathDir := range pathDirs {
		if pathDir == absDir {
			fmt.Printf("目录 %s 已经在PATH中\n", absDir)
			return nil
		}
	}

	// 将新目录添加到PATH前面（优先级更高）
	newPath := absDir + string(os.PathListSeparator) + currentPath

	// 设置新的PATH环境变量
	err = os.Setenv("PATH", newPath)
	if err != nil {
		return fmt.Errorf("设置PATH失败: %v", err)
	}

	fmt.Printf("已添加目录到PATH: %s\n", absDir)
	return nil
}

// [{\"bus_id\":\"2-2\",\"guid\":\"2bdf:0280\",\"vendor\":\"unknown vendor\",\"product\":\"unknown product\",\"port\":1}]
func (u *UsbIpClientWindowsCmdServiceImpl) PortList() []*vo.UsbInfo {
	str, err := exec.Command("usbip", "port").CombinedOutput()
	if err != nil {
		log.Errorf("UsbIpClientWindowsCmdServiceImpl Port err:%v", err)
		return nil
	}

	result := parseWindowsUsbipPortOutput(string(str))
	resultJson, _ := json.Marshal(result)
	log.Debugf("UsbIpClientWindowsCmdServiceImpl Port result:%v err:%v", string(resultJson), err)
	return result
}

func (u *UsbIpClientWindowsCmdServiceImpl) DetachPort(port int) error {
	cmdStrs := []string{"usbip", "detach", "-p", fmt.Sprintf("%d", port)}
	str, err := exec.Command(cmdStrs[0], cmdStrs[1:]...).CombinedOutput()
	if err != nil {
		log.Errorf("UsbIpClientWindowsCmdServiceImpl DetachPort err:%v str:%v", err, string(str))
		return nil
	}

	//result := parseWindowsUsbipPortOutput(string(str))
	log.Infof("UsbIpClientWindowsCmdServiceImpl DetachPort result:%v err:%v", string(str), err)
	return nil
}

func (u *UsbIpClientWindowsCmdServiceImpl) DetachByBusId(busId, vendorId string) error {
	portList := u.PortList()

	for _, port := range portList {
		if port.BusId == busId {
			if vendorId == "" || port.VendorId == vendorId {
				u.DetachPort(port.Port)
			}
			log.Infof("UsbIpClientWindowsCmdServiceImpl DetachByBusId port:%+v vendorId:%v", port, vendorId)
			return nil
		}
	}

	log.Infof("UsbIpClientWindowsCmdServiceImpl DetachByBusId not find busId:%v", busId)
	return nil
}

func NewUsbIpClientWindowsCmdServiceImpl(platformHandle platform.PlatformHandler) UsbIpClientCmdService {
	impl := &UsbIpClientWindowsCmdServiceImpl{
		//attachMap:      make(map[int64]bool),
		platformHandle: platformHandle,
	}

	onceRun.Do(func() {
		/*
			go func() {
				if err := impl.ensureAudioDeviceModule(); err != nil {
					log.Infof("模块安装失败: %v", err)
				}
			}()
		*/
	})

	return impl
}

func parseWindowsUsbipPortOutput(output string) []*vo.UsbInfo {
	var usbInfos []*vo.UsbInfo
	scanner := bufio.NewScanner(strings.NewReader(output))

	// 定义正则表达式
	portRegex := regexp.MustCompile(`Port (\d+):\s+(.*)`)
	vendorProductRegex := regexp.MustCompile(`\s+([^:]+)\s*:\s*([^(\n]+)\s*\(([0-9a-fA-F]+:[0-9a-fA-F]+)\)`)
	busIdRegex := regexp.MustCompile(`-> usbip://[^/]+/(\d+-\d+)`)

	var currentInfo *vo.UsbInfo
	var inDeviceBlock bool

	for scanner.Scan() {
		line := scanner.Text()

		// 检查是否为端口行
		if portRegex.MatchString(line) {
			// 如果之前有设备信息，添加到结果中
			if inDeviceBlock {
				usbInfos = append(usbInfos, currentInfo)
				inDeviceBlock = false
			}

			matches := portRegex.FindStringSubmatch(line)
			if len(matches) >= 3 {
				// 重置当前设备信息
				currentInfo = &vo.UsbInfo{}
				inDeviceBlock = true

				// 解析端口号
				fmt.Sscanf(matches[1], "%d", &currentInfo.Port)

				// 解析状态
				if strings.Contains(matches[2], "not used") {
					currentInfo.State = 0
				} else {
					currentInfo.State = 1
				}
			}
			continue
		}

		// 如果不在设备块中，继续
		if !inDeviceBlock {
			continue
		}

		// 解析厂商和产品信息
		if vendorProductRegex.MatchString(line) {
			matches := vendorProductRegex.FindStringSubmatch(line)
			if len(matches) >= 4 {
				currentInfo.Vendor = strings.TrimSpace(matches[1])
				currentInfo.Product = strings.TrimSpace(matches[2])
				currentInfo.VendorId = matches[3]
			}
			continue
		}

		// 解析总线ID (格式: 2-4)
		if busIdRegex.MatchString(line) {
			matches := busIdRegex.FindStringSubmatch(line)
			if len(matches) >= 2 {
				currentInfo.BusId = matches[1]
			}
		}
	}

	// 添加最后一个设备信息
	if inDeviceBlock {
		usbInfos = append(usbInfos, currentInfo)
	}

	return usbInfos
}
